﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Markup;
using System.ComponentModel;
using System.Windows.Media.Imaging;

namespace BrainTechLLC.Silverlight.Controls
{
    public partial class DataVisualizer : WindowContainer, IUICanOpenClose
    {
        public event EventHandler<ObjectEventArgs<LocationInt>> RequestGoLocation;
        public event EventHandler<ObjectEventArgs<LocationInt>> RequestEditGameLocation;
        public event EventHandler<ObjectEventArgsNonRef<long>> RequestEditID;

        protected IDataVisualizer _visualizer;
        protected ComboBox _comboBox;
        protected bool _dataChanged;
        protected bool _needsNewVisualizer;

        public static readonly DependencyProperty ShowVisualizerSelectionObjectProperty = DependencyProperty.Register(
            "ShowVisualizerSelectionObject", typeof(bool), typeof(DataVisualizer), new PropertyMetadata(false, new PropertyChangedCallback(ShowVisualizerSelectionChanged)));

        public static readonly DependencyProperty VisualizerTypeProperty = DependencyProperty.Register(
            "VisualizerType", typeof(Type), typeof(DataVisualizer), new PropertyMetadata(null, new PropertyChangedCallback(VisualizerTypeChanged)));

        public static readonly DependencyProperty VisualizerNameProperty = DependencyProperty.Register(
            "VisualizerName", typeof(string), typeof(DataVisualizer), new PropertyMetadata(string.Empty, new PropertyChangedCallback(VisualizerNameChanged)));

        public static readonly DependencyProperty IsCollectionProperty = DependencyProperty.Register(
            "IsCollection", typeof(bool), typeof(DataVisualizer), new PropertyMetadata(false, new PropertyChangedCallback(IsCollectionChanged)));

        public static readonly DependencyProperty DataToVisualizeProperty = DependencyProperty.Register(
            "DataToVisualize", typeof(object), typeof(DataVisualizer), new PropertyMetadata(null, new PropertyChangedCallback(DataToVisualizeChanged)));

        public static readonly DependencyProperty OwnerProperty = DependencyProperty.Register(
            "Owner", typeof(object), typeof(DataVisualizer), new PropertyMetadata(null, new PropertyChangedCallback(OwnerChanged)));

        public object Owner
        {
            get { return (object)GetValue(OwnerProperty); }
            set { SetValue(OwnerProperty, value); }
        }

        private static void OwnerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HandleChange<object>(d, e, (t, val) => t.Owner = val);
        }

        private static void ContentBackgroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HandleChange<Brush>(d, e, (t, val) => t.ContentBackground = val);
        }

        private static void WindowBorderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HandleChange<Brush>(d, e, (t, val) => t.WindowBorder = val);
        }

        private static void HeaderBackgroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HandleChange<Brush>(d, e, (t, val) => t.HeaderBackground = val);
        }

        private static void DescriptionTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HandleChange<string>(d, e, (t, val) => t.DescriptionTextString = val);
        }

        public static void HandleChange<T2>(DependencyObject d, DependencyPropertyChangedEventArgs e, Action<DataVisualizer, T2> action)
        {
            d.HandleChange<DataVisualizer, T2>(e, action, (t) => t.UpdateBindings());
        }

        public IDataVisualizer Visualizer
        {
            get { return _visualizer; }
        }

        public bool ShowVisualizerSelection
        {
            get { return (bool)GetValue(ShowVisualizerSelectionObjectProperty); }
            set
            {
                if (ShowVisualizerSelection != value) _dataChanged = true;
                SetValue(ShowVisualizerSelectionObjectProperty, value);
            }
        }

        private static void ShowVisualizerSelectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HandleChange<bool>(d, e, (t, val) => t.ShowVisualizerSelection = val);
        }

        public DataVisualizerInfo VisualizerInfo
        {
            get { return DataVisualizerRegistry.Instance.FindVisualizer(VisualizerType, VisualizerName, IsCollection); }
        }

        public override void Refresh()
        {
            base.Refresh();
            UpdateBindings();
        }

        public Type VisualizerType
        {
            get { return (Type)GetValue(VisualizerTypeProperty); }
            set
            {
                if (VisualizerType != value) _needsNewVisualizer = true;
                SetValue(VisualizerTypeProperty, value);
            }
        }

        private static void VisualizerTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((DataVisualizer)d).VisualizerType = e.NewValue as Type;
        }


        public string VisualizerName
        {
            get { return (string)GetValue(VisualizerNameProperty); }
            set
            {
                if (VisualizerName != value) _needsNewVisualizer = true;
                SetValue(VisualizerNameProperty, value);
            }
        }

        private static void VisualizerNameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HandleChange<string>(d, e, (t, val) => t.VisualizerName = val);
        }

        public bool IsCollection
        {
            get { return (bool)GetValue(IsCollectionProperty); }
            set
            {
                if (IsCollection != value) _needsNewVisualizer = true;
                SetValue(IsCollectionProperty, value);
            }
        }

        private static void IsCollectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HandleChange<bool>(d, e, (t, val) => t.IsCollection = val);
        }

        private static void WindowlessModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HandleChange<bool>(d, e, (t, val) => t.WindowlessMode = val);
        }

        public object DataToVisualize
        {
            get { return (object)GetValue(DataToVisualizeProperty); }
            set
            {
                if (DataToVisualize != value) _dataChanged = true;
                SetValue(DataToVisualizeProperty, value);
            }
        }

        private static void DataToVisualizeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataVisualizer t = (DataVisualizer)d;
            HandleChange<object>(d, e, (ctrl, val) => ctrl.DataToVisualize = val);

            if (t.DataToVisualize == null && t.Visibility != Visibility.Collapsed)
                t.Visibility = Visibility.Collapsed;
            else if (t.DataToVisualize != null && t.Visibility != Visibility.Visible)
                t.Visibility = Visibility.Visible;
        }

        public void SetVisualizerTypeBasedOnData(object data)
        {
            if (data == null)
                return;

            Type t = data.GetType();
            if (t.IsGenericType)
            {
                IsCollection = true;
                Type[] types = t.GetGenericArguments();
                t = types[0];
            }
            else
            {
                IsCollection = false;
            }

            if (VisualizerType != t)
                VisualizerType = t;
        }

        public DataVisualizer()
            : base()
        {
            DefaultStyleKey = typeof(DataVisualizer);
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            if (_content == null)
            {
                _content = base.GetTemplateChild("PART_Content") as ContentPresenter;
            }

            _content.Loaded += new RoutedEventHandler(_content_Loaded);
            _content.LayoutUpdated += new EventHandler(_content_LayoutUpdated);
        }

        void _content_LayoutUpdated(object sender, EventArgs e)
        {
            if (_visualizer != null && (_content.Content == null || !_content.Content.Equals(_visualizer)))
                Refresh();
        }

        public void SetVisualizer()
        {
            DataVisualizerInfo vi = VisualizerInfo;

            if (vi == null || DataToVisualize == null)
                return;

            _needsNewVisualizer = false;

            if (_visualizer != null)
            {
                if (_visualizer.VisualizerName == VisualizerName && _visualizer.VisualizeType == VisualizerType)
                    return;

                _visualizer.WantClose -= _visualizer_WantClose;
                _visualizer.CloseWindow -= _visualizer_CloseWindow;
                _visualizer.RequestEditID -= _visualizer_RequestEditID;
                _visualizer.RequestGoLocation -= _visualizer_RequestGoLocation;
                _visualizer.RequestEditGameLocation -= _visualizer_RequestEditGameLocation;
                _visualizer = null;
            }

            _visualizer = vi.CreateVisualizer() as IDataVisualizer;
            _visualizer.RequestEditID += new EventHandler<ObjectEventArgsNonRef<long>>(_visualizer_RequestEditID);
            _visualizer.RequestGoLocation += new EventHandler<ObjectEventArgs<LocationInt>>(_visualizer_RequestGoLocation);
            _visualizer.WantClose += new EventHandler<ObjectEventArgsNonRef<bool>>(_visualizer_WantClose);
            _visualizer.CloseWindow += new EventHandler(_visualizer_CloseWindow);
            _visualizer.RequestEditGameLocation += new EventHandler<ObjectEventArgs<LocationInt>>(_visualizer_RequestEditGameLocation);

            if (_content == null)
                _content = base.GetTemplateChild("PART_Content") as ContentPresenter;

            if (_content == null)
                _content = this.FindName("PART_Content") as ContentPresenter;

            if (_content != null)
            {
                _content.Content = _visualizer;
                _visualizer.SetVisualizedData(this, DataToVisualize);
            }
        }

        void _visualizer_RequestEditGameLocation(object sender, ObjectEventArgs<LocationInt> e)
        {
            OnRequestEditGameLocation(sender, e);
        }

        void _visualizer_RequestGoLocation(object sender, ObjectEventArgs<LocationInt> e)
        {
            OnRequestGoToLocation(sender, e);
        }

        public void OnRequestGoToLocation(object sender, ObjectEventArgs<LocationInt> e)
        {
            if (RequestGoLocation != null)
                RequestGoLocation(this, e);
        }

        public void OnRequestEditGameLocation(object sender, ObjectEventArgs<LocationInt> e)
        {
            if (RequestEditGameLocation != null)
                RequestEditGameLocation(this, e);
        }

        void _visualizer_RequestEditID(object sender, ObjectEventArgsNonRef<long> e)
        {
            if (RequestEditID != null)
                RequestEditID(sender, e);
        }

        public int _reentranceCheck = 0;

        void _visualizer_WantClose(object sender, ObjectEventArgsNonRef<bool> e)
        {
            if (_reentranceCheck > 0)
            {
                _reentranceCheck = 0;
                return;
            }
            _reentranceCheck = 1;
            OnWantClose(sender, e);
            _reentranceCheck = 0;
        }

        void _visualizer_CloseWindow(object sender, EventArgs e)
        {
            OnCloseWindow(sender, e);
        }

        void _content_Loaded(object sender, RoutedEventArgs e)
        {
            if (_visualizer != null && DataToVisualize != null)
                _visualizer.SetVisualizedData(this, DataToVisualize);
        }


        protected void UpdateBindings()
        {
            if (_content != null)
            {
                if (_visualizer == null || _needsNewVisualizer || _dataChanged)
                {
                    if (DataToVisualize != null)
                        SetVisualizerTypeBasedOnData(DataToVisualize);
                }

                if (_visualizer == null || _needsNewVisualizer)
                {
                    _dataChanged = true;
                    SetVisualizer();
                }
                else if (_dataChanged)
                {
                    _dataChanged = false;

                    if (_visualizer != null)
                    {
                        _visualizer.SetVisualizedData(this, DataToVisualize);
                    }
                }

                if (_visualizer != null)
                {
                    if (_updatedSaveButton && _visualizer.MainCanvas != null)
                    {
                        _updatedSaveButton = false;
                        _visualizer.MainCanvas.ForEachRecursive<WindowContainer>((wc) => wc.ShowSave = ShowSave, null);
                    }

                    bool showingVisualizerSelection = (_comboBox != null);

                    if (ShowVisualizerSelection && !showingVisualizerSelection)
                    {
                        _comboBox = new ComboBox()
                        {
                            FontSize = 9D,
                            HorizontalAlignment = HorizontalAlignment.Right,
                            VerticalAlignment = VerticalAlignment.Center,
                            Width = 120,
                            Height = 18,
                            Margin = new Thickness(0, 1, 0, 1),
                            Padding = new Thickness(2, 1, 2, 1)
                        };

                        List<DataVisualizerInfo> visualizers = DataVisualizerRegistry.Instance.FindVisualizersForType(VisualizerType, IsCollection);

                        _comboBox.DisplayMemberPath = "VisualizerName";
                        _comboBox.ItemsSource = visualizers;
                        _comboBox.SelectedItem = VisualizerInfo;
                        _comboBox.SelectionChanged += new SelectionChangedEventHandler(_comboBox_SelectionChanged);
                        Grid.SetColumn(_comboBox, 1);
                        _stacker.Children.Insert(0, _comboBox);
                    }
                    else if (!ShowVisualizerSelection && showingVisualizerSelection)
                    {
                        if (_comboBox != null)
                        {
                            _comboBox.SelectionChanged -= _comboBox_SelectionChanged;
                            _stacker.Children.Remove(_comboBox);
                            _comboBox.ItemsSource = null;
                            _comboBox = null;
                        }
                    }
                }
            }
        }

        void _comboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (_comboBox.SelectedItem != null && _comboBox.SelectedItem as DataVisualizerInfo != VisualizerInfo)
            {
                DataVisualizerInfo vis = _comboBox.SelectedItem as DataVisualizerInfo;
                _needsNewVisualizer = true;
                _dataChanged = true;
                VisualizerName = vis.VisualizerName;
            }
        }
    }
}


